﻿ArithmeticTests = function () {
    this.Name = "Arithmetic Tests";
};

ArithmeticTests.prototype = new TestFixture();

ArithmeticTests.prototype.TestAddition = function () {
    var vm = new VM();

    // 1 + 2 + 3 + 4 = 10
    vm.Execute("ldc.i4 1");
    vm.Execute("ldc.i4 2");
    vm.Execute("ldc.i4 3");
    vm.Execute("ldc.i4 4");
    vm.Execute("add");
    vm.Execute("add");
    vm.Execute("add");

    var result = vm.State.Stack.Top();
    this.Assert(10, result.Value);
};

ArithmeticTests.prototype.TestSubtraction = function () {
    var vm = new VM();

    // 20 - (10 - 5) = 15
    vm.Execute("ldc.i4 20");
    vm.Execute("ldc.i4 10");
    vm.Execute("ldc.i4 5");
    vm.Execute("sub");
    vm.Execute("sub");

    var result = vm.State.Stack.Top();
    this.Assert(15, result.Value);
};

ArithmeticTests.prototype.TestCombined = function() {
    var vm = new VM();

    // 20 + 10 - 5 = 25
    vm.Execute("ldc.i4 20");
    vm.Execute("ldc.i4 10");
    vm.Execute("add");
    vm.Execute("ldc.i4 5");
    vm.Execute("sub");

    var result = vm.State.Stack.Top();
    this.Assert(25, result.Value);
};

ArithmeticTests.prototype.TestMultiplication = function() {
    var vm = new VM();

    // 5 * 4 * 2 = 40
    vm.Execute("ldc.i4 5");
    vm.Execute("ldc.i4 4");
    vm.Execute("ldc.i4 2");
    vm.Execute("mul");
    vm.Execute("mul");

    var result = vm.State.Stack.Top();
    this.Assert(40, result.Value);
};

ArithmeticTests.prototype.TestProgram = function () {
    var vm = new VM();
    var commands = [];


    // 5 * 4 * 2 = 40
    commands.push("ldc.i4 5");
    commands.push("ldc.i4 4");
    commands.push("ldc.i4 2");
    commands.push("mul");
    commands.push("mul");

    vm.ExecuteProgram(commands);

    var result = vm.State.Stack.Top();
    this.Assert(40, result.Value);
};

ArithmeticTests.prototype.TestStoreLocal = function () {
    var vm = new VM();
    vm.Execute("ldc.i4 5");
    vm.Execute("stloc 0");
    var result = vm.State.Locals.Get(0);
    this.Assert(5, result.Value);
};

ArithmeticTests.prototype.TestLoadLocal = function () {
    var vm = new VM();
    var localValue = new StackEntry();
    localValue.Type = "i4";
    localValue.Value = 10;
    vm.State.Locals.Set(0, localValue);

    vm.Execute("ldloc 0");
    var result = vm.State.Locals.Get(0);
    this.Assert(10, result.Value);
};

ArithmeticTests.prototype.TestMemoryRoundTrip = function () {
    var vm = new VM();

    // put a couple values on stack
    vm.Execute("ldc.i4 10");
    vm.Execute("ldc.i4 20");

    // store them to local memory
    vm.Execute("stloc 1");              // loc 1 = 20
    vm.Execute("stloc.0");              // loc 0 = 10

    // put them back on stack in reverse order
    vm.Execute("ldloc.1");              // loc 1 = 20
    vm.Execute("ldloc 0");              // loc 0 = 10

    var top = vm.State.Stack.Pop();
    this.Assert(10, top.Value);

    top = vm.State.Stack.Pop();
    this.Assert(20, top.Value);
    
    this.Assert(10, vm.State.Locals.Get(0).Value);
    this.Assert(20, vm.State.Locals.Get(1).Value);
};


// - and -
// 0111010011110 = 3742
// 0110110011010 = 3482
// -------------
// 0110010011010 =  3226
ArithmeticTests.prototype.TestAnd = function () {
    var vm = new VM();
    vm.Execute("ldc.i4 3742");
    vm.Execute("ldc.i4 3482");
    vm.Execute("and");
    var result = vm.State.Stack.Top();
    this.Assert(3226, result.Value);
};

// - or -
// 0111010011110 = 3742
// 0110110011010 = 3482
// -------------
// 0111110011110 =  3998
ArithmeticTests.prototype.TestOr = function () {
    var vm = new VM();
    vm.Execute("ldc.i4 3742");
    vm.Execute("ldc.i4 3482");
    vm.Execute("or");
    var result = vm.State.Stack.Top();
    this.Assert(3998, result.Value);
};

// - xor -
// 0111010011110 = 3742
// 0110110011010 = 3482
// -------------
// 0001100000100 =  772
ArithmeticTests.prototype.TestXor = function () {
    var vm = new VM();
    vm.Execute("ldc.i4 3742");
    vm.Execute("ldc.i4 3482");
    vm.Execute("xor");
    var result = vm.State.Stack.Top();
    this.Assert(772, result.Value);
};

// - not -
// 0111010011110 = 3742
// -------------
// 1000101100001 =  -3743
ArithmeticTests.prototype.TestNot = function () {
    var vm = new VM();
    vm.Execute("ldc.i4 3742");
    vm.Execute("not");
    var result = vm.State.Stack.Top();
    this.Assert(-3743, result.Value);
};

ArithmeticTests.prototype.TestShiftLeft = function () {
    var vm = new VM();
    vm.Execute("ldc.i4 129");
    vm.Execute("ldc.i4 3");
    vm.Execute("shl");
    var result = vm.State.Stack.Top();
    this.Assert(1032, result.Value);
};

ArithmeticTests.prototype.TestShiftRight = function () {
    var vm = new VM();
    vm.Execute("ldc.i4 16");
    vm.Execute("ldc.i4 3");
    vm.Execute("shr");
    var result = vm.State.Stack.Top();
    this.Assert(2, result.Value);
};

ArithmeticTests.prototype.TestShiftRightWithSign = function () {
    var vm = new VM();
    vm.Execute("ldc.i4 -16");
    vm.Execute("ldc.i4 3");
    vm.Execute("shr");
    var result = vm.State.Stack.Top();
    this.Assert(-2, result.Value);
};

ArithmeticTests.prototype.TestShiftRightUnsigned = function () {
    var vm = new VM();
    vm.Execute("ldc.i4 -16");
    vm.Execute("ldc.i4 3");
    vm.Execute("shr.un");
    var result = vm.State.Stack.Top();
    this.Assert(536870910, result.Value);
};

ArithmeticTests.prototype.TestNeg = function () {
    var vm = new VM();
    vm.Execute("ldc.i4 -16");
    vm.Execute("neg");
    var result = vm.State.Stack.Top();
    this.Assert(16, result.Value);
};

ArithmeticTests.prototype.TestDup = function () {
    var vm = new VM();
    vm.Execute("ldc.i4 10");
    vm.Execute("dup");
    var result = vm.State.Stack.Top();
    this.Assert(10, result.Value);

    vm.Execute("ldc.i4 2");
    vm.Execute("add");

    result = vm.State.Stack.Pop();
    this.Assert(12, result.Value);

    result = vm.State.Stack.Top();
    this.Assert(10, result.Value);
};

ArithmeticTests.prototype.Template = function () {
    var vm = new VM();
    vm.Execute("ldc.i4 4");
    vm.Execute("ldc.i4 4");
    var result = vm.State.Stack.Top();
    this.Assert(3, result.Value);
};


/*ArithmeticTests.prototype.TestBranchEqual = function () {
    var vm = new VM();
    var commands = [];

    // for i = 1 to 5
    
    commands.push("ldc.i4 5");
    commands.push("ldc.i4 4");
    commands.push("ldc.i4 2");
    commands.push("mul");
    commands.push("mul");

    vm.ExecuteProgram(commands);

    var result = vm.State.Stack.Top();
    this.Assert(40, result.Value);
};*/
